package com.gzz.orchid.common.core.util;


import com.gzz.orchid.common.core.exception.ArgumentException;
import com.gzz.orchid.common.core.support.SnowFlake;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Objects;
import java.util.Random;

/**
 * 订单号生成
 *
 * @author higmd
 */
public class IdNoUtil {
    public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyMMdd");

    // 获取当前日期格式
    private static String dateGen() {
        return LocalDate.now().format(FORMATTER);
    }

    /**
     * 返回唯一雪花的ID（18位）
     */
    public static Long buildId() {
        return SnowFlake.instance().nextId();
    }

    /**
     * 每天序列号（14位）
     */
    public static Long buildSeg() {
        return Long.parseLong(buildNo());
    }

    /**
     * 每天序列号（12位）
     */
    public static String buildNo() {
        String id = String.valueOf(SnowFlake.instance().nextId());
        return dateGen() + id.substring(id.length() - 6);
    }

    /**
     * 自定义开头预列号
     *
     * @param prefix 指定开头
     */
    public static String buildNo(String prefix) {
        if (Objects.isNull(prefix)) {
            throw new ArgumentException("前缀不能为空");
        }
        return prefix.toUpperCase() + buildNo();
    }

    //--------------------------------------------------------------------------------

    /**
     * 生成随机不重复数，最长10位
     * <p>
     * 这是典型的随机洗牌算法。
     * 流程是从备选数组中选择一个放入目标数组中，将选取的数组从备选数组移除(放至最后，并缩小选择区域)
     * 算法时间复杂度O(n)
     */
    public static String buildRepeatId(int len) {
        if (len < 1 || len > 10) {
            throw new ArgumentException("生成长度有效值在[1 ~ 10]之间");
        }
        //初始化备选数组
        int[] defaultNums = new int[15];
        for (int i = 0; i < defaultNums.length; i++) {
            defaultNums[i] = i;
        }

        Random random = new Random();
        int[] nums = new int[len];
        //默认数组中可以选择的部分长度
        int canBeUsed = 10;
        //填充目标数组
        for (int i = 0; i < nums.length; i++) {
            //将随机选取的数字存入目标数组
            int index = random.nextInt(canBeUsed);
            nums[i] = defaultNums[index];
            //将已用过的数字扔到备选数组最后，并减小可选区域
            swap(index, canBeUsed - 1, defaultNums);
            canBeUsed--;
        }
        StringBuilder no = new StringBuilder();
        for (int i : nums) {
            no.append(i);
        }
        return no.toString();
    }

    // 交换
    private static void swap(int i, int j, int[] nums) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

    /**
     * 测试
     */
    public static void main(String[] args) {
        //System.out.println(System.currentTimeMillis());
        long startTime = System.nanoTime();
        //
        for (int i = 0; i < 50; i++) {
            try {
                System.out.println(IdNoUtil.buildNo());
            } catch (Exception e) {
                //System.out.println(e.getMessage());
            }
            //System.out.println(IdNoUtil.buildNo());
            //System.out.println(IdNoUtil.buildNORepeatID(10));
            //System.out.println(IdNoUtil.buildId());
        }
        System.out.println("花费时间：： " + (System.nanoTime() - startTime) / 1000000 + "ms");
        String nxt = "2232lkdfadkj3i中中";
        System.out.println("花费时间：： " + nxt.hashCode());
        System.out.println("花费时间：： " + (nxt.hashCode() & Integer.MIN_VALUE));


        System.out.println("2>>20：： " + (2 << 10));

    }
}
